﻿using System.Diagnostics.Contracts;

namespace System.Reflection
{
    public class Field<TObject, TValue>
    {
        private FieldInfo f_Info;
        private string f_Name;
        private TObject f_Object;
        private bool f_Private;

        public bool IsExist { get { return f_Info != null; } }

        public string Name { get { return f_Name; } set { Initialize(f_Object, f_Name = value, f_Private); } }

        public TObject Object { get { return f_Object; } set { Initialize(f_Object = value, f_Name, f_Private); } }

        public bool Private { get { return f_Private; } set { Initialize(f_Object, f_Name, f_Private = value); } }

        public TValue Value { get { return (TValue)f_Info.GetValue(f_Object); } set { f_Info.SetValue(f_Object, value); } }

        public Field(TObject o, string Name, bool Private = false)
        {
            Initialize(f_Object = o, f_Name = Name, f_Private = Private);
        }

        private void Initialize(TObject o, string Name, bool Private)
        {
            Contract.Requires(!string.IsNullOrEmpty(Name));

            var type = typeof(TObject);
            if(type == typeof(TObject) && o != null)
                type = o.GetType();

            var IsPrivate = Private ? BindingFlags.NonPublic : BindingFlags.Public;
            var IsStatic = ReferenceEquals(o, null) ? BindingFlags.Static : BindingFlags.Instance;

            f_Info = type.GetField(Name, IsPrivate | IsStatic);
        }
    }
}